package cn.tedu.blackhorse.service.impl;

import cn.tedu.blackhorse.ex.ServiceCode;
import cn.tedu.blackhorse.ex.ServiceException;
import cn.tedu.blackhorse.mapper.AdminMapper;
import cn.tedu.blackhorse.mapper.PermissionMapper;
import cn.tedu.blackhorse.mapper.TeacherMapper;
import cn.tedu.blackhorse.pojo.dto.AdminAddNewDTO;
import cn.tedu.blackhorse.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.blackhorse.pojo.dto.AdminUpdateDTO;
import cn.tedu.blackhorse.pojo.dto.AdminUpdatePasswordDTO;
import cn.tedu.blackhorse.pojo.entity.Admin;
import cn.tedu.blackhorse.pojo.vo.AdminListItemVO;
import cn.tedu.blackhorse.pojo.vo.AdminStandardVO;
import cn.tedu.blackhorse.pojo.vo.PermissionStandardVO;
import cn.tedu.blackhorse.pojo.vo.TeacherStandardVO;
import cn.tedu.blackhorse.security.AdminDetails;
import cn.tedu.blackhorse.service.IAdminService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class AdminServiceImpl implements IAdminService {
    @Value("${BH.jwt.secret-key}")
    private String secretKey;
    @Value("${BH.jwt.duration-in-minute}")
    private Long time;

    @Autowired
    private TeacherMapper teacherMapper;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;


    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理管理员登录");
        // 调用AuthenticationManager的authenticate()方法执行认证
        // 在authenticate()方法的执行过程中
        // Spring Security会自动调用UserDetailsService对象的loadUserByUsername()获取用户详情
        // 并根据loadUserByUsername()返回的用户详情自动验证是否启用、判断密码是否正确等
        Authentication authentication =
                new UsernamePasswordAuthenticationToken(
                        adminLoginInfoDTO.getUsername(),
                        adminLoginInfoDTO.getPassword());
        log.debug("输入的信息为:{}",adminLoginInfoDTO);
        Authentication authenticationResult =
                authenticationManager.authenticate(authentication);
        log.debug("Spring Security 已经完成认证,且认证通过,认证结果为{}", authenticationResult);
        log.debug("返回认证信息中的当事人(Principal) 类型:{}", authenticationResult.getPrincipal());
        log.debug("返回认证信息中的当事人(Principal) 数据:{}", authenticationResult.getPrincipal());
        AdminDetails principal = (AdminDetails) authenticationResult.getPrincipal();
        //获取用户名
        String username = principal.getUsername();
        //获取权限
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        log.debug("认证信息中的权限:{}", authorities);
        Long id = principal.getId();
        log.debug("认证信息中的id:{}", id);
        String authorityJSONListString = JSON.toJSONString(authorities);
        log.debug("认证信息中的权限转化为JSON编码格式之后的数据:{}", authorityJSONListString);


        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authorities", authorityJSONListString);


        Date expiration = new Date(System.currentTimeMillis() + time * 60 * 1000);
        log.debug("即将生成JWT数据，过期时间：{}", expiration);


        // JWT的组成：Header（头：算法和Token类型）、Payload（载荷）、Signature（签名）
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();

        log.debug("已经生成JWT数据：{}", jwt);
        //生成JWT
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        TeacherStandardVO standard = teacherMapper.getById(adminAddNewDTO.getTeacherId());
        if (standard == null){
            String message = "添加失败,添加的老师未找到";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        int count = adminMapper.countByName(adminAddNewDTO.getUsername());
        if (count != 0){
            String message = "添加失败,用户名已存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        PermissionStandardVO permission = permissionMapper.getById(adminAddNewDTO.getPermissionId());
        if (permission == null){
            String message = "添加失败,添加所选权限不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        int row = adminMapper.insert(admin);
        if (row != 1){
            String message = "添加管理员失败,系统繁忙请稍后重试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        return adminMapper.list();
    }

    @Override
    public void deleteById(Long id) {
        AdminStandardVO standard = adminMapper.getById(id);
        if (standard == null){
            String message = "删除失败,所删除的对象不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        int row = adminMapper.deleteById(id);
        if (row != 1){
           String message = "删除失败,系统繁忙请稍后重试";
           log.debug(message);
           throw new ServiceException(ServiceCode.ERR_DELETE,message);
        }
    }

    @Override
    public void setEnable(Long id) {
        AdminStandardVO standard = adminMapper.getById(id);
        if (standard == null){
            String message = "启用失败,启用对象未找到";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        if (standard.getEnable() == 1){
            String message= "启用失败,对象所选对象已经启用";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(1);
        int row = adminMapper.updateById(admin);
        if (row != 1){
            String message = "启用失败,系统繁忙请稍后重试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

    @Override
    public void setDisable(Long id) {
        AdminStandardVO standard = adminMapper.getById(id);
        if (standard == null){
            String message = "禁用失败,启用对象未找到";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        if (standard.getEnable() == 0){
            String message= "禁用失败,对象所选对象已经禁用";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(0);
        int row = adminMapper.updateById(admin);
        if (row != 1){
            String message = "禁用失败,系统繁忙请稍后重试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

    @Override
    public void setPassword(AdminUpdatePasswordDTO adminUpdatePasswordDTO) {
        AdminStandardVO standardVO = adminMapper.getById(adminUpdatePasswordDTO.getId());
        if (standardVO == null){
            String message = "修改失败,修改用户不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        Admin admin = new Admin();
        admin.setPassword(adminUpdatePasswordDTO.getPassword());
        admin.setId(adminUpdatePasswordDTO.getId());
        int row = adminMapper.updateById(admin);
        if (row != 1){
            String message = "修改失败,系统繁忙请稍后重试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

    @Override
    public void setData(Long id,AdminUpdateDTO adminUpdateDTO) {
        AdminStandardVO standardVO = adminMapper.getById(id);
        if (standardVO == null){
            String message = "修改失败,修改用户不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminUpdateDTO,admin);
        admin.setId(id);
        int row = adminMapper.updateById(admin);
        if (row != 1){
            String message = "修改失败,系统繁忙请稍后重试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }
}
